🎖️GitЯра🎖️
Node / meshtastic / Meshtastic-Android / files / core / model / src / commonMain / kotlin / org / meshtastic / core / model / Node.kt
Displaying Raw • Download
core/model/src/commonMain/kotlin/org/meshtastic/core/model/Node.kt bd2863243bab6eb213401d949839a2bc74dde7e2 (bd286324) Text, 11.02 KB
T8b949e/*
* Copyright (c) 2026 Meshtastic LLC
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
Tff7b72package T7ee787org.meshtastic.core.model
Tff7b72import T7ee787okio.ByteString
Tff7b72import T7ee787okio.ByteString.Companion.toByteString
Tff7b72import T7ee787org.meshtastic.core.common.util.GPSFormat
Tff7b72import T7ee787org.meshtastic.core.common.util.MetricFormatter
Tff7b72import T7ee787org.meshtastic.core.common.util.bearing
Tff7b72import T7ee787org.meshtastic.core.common.util.latLongToMeter
Tff7b72import T7ee787org.meshtastic.core.model.util.onlineTimeThreshold
Tff7b72import T7ee787org.meshtastic.core.model.util.toDistanceString
Tff7b72import T7ee787org.meshtastic.proto.AirQualityMetrics
Tff7b72import T7ee787org.meshtastic.proto.Config
Tff7b72import T7ee787org.meshtastic.proto.DeviceMetadata
Tff7b72import T7ee787org.meshtastic.proto.DeviceMetrics
Tff7b72import T7ee787org.meshtastic.proto.EnvironmentMetrics
Tff7b72import T7ee787org.meshtastic.proto.HardwareModel
Tff7b72import T7ee787org.meshtastic.proto.MeshPacket
Tff7b72import T7ee787org.meshtastic.proto.Paxcount
Tff7b72import T7ee787org.meshtastic.proto.Position
Tff7b72import T7ee787org.meshtastic.proto.PowerMetrics
Tff7b72import T7ee787org.meshtastic.proto.User
T8b949e/**
* Domain model representing a node in the mesh network.
*
* This class aggregates user information, position data, and hardware metrics.
*/
Tf0883e@SuppressTb4b4b4(Ta5d6ff"Ta5d6ffMagicNumberTa5d6ff"Tb4b4b4)
Tff7b72data Tff7b72class T56d364NodeTb4b4b4(
Tff7b72val Te6edf3numTb4b4b4: Tffa657IntTb4b4b4,
Tff7b72val Te6edf3metadataTb4b4b4: Te6edf3DeviceMetadata? Tff7b72= Tff7b72nullTb4b4b4,
Tff7b72val Te6edf3userTb4b4b4: Te6edf3User Tff7b72= Te6edf3UserTb4b4b4(Tb4b4b4)Tb4b4b4,
Tff7b72val Te6edf3positionTb4b4b4: Te6edf3Position Tff7b72= Te6edf3PositionTb4b4b4(Tb4b4b4)Tb4b4b4,
Tff7b72val Te6edf3snrTb4b4b4: Tffa657Float Tff7b72= Tffa657FloatTb4b4b4.Te6edf3MAX_VALUETb4b4b4,
Tff7b72val Te6edf3rssiTb4b4b4: Tffa657Int Tff7b72= Tffa657IntTb4b4b4.Te6edf3MAX_VALUETb4b4b4,
Tff7b72val Te6edf3lastHeardTb4b4b4: Tffa657Int Tff7b72= T79c0ff0Tb4b4b4, T8b949e// the last time we've seen this node in secs since 1970
Tff7b72val Te6edf3deviceMetricsTb4b4b4: Te6edf3DeviceMetrics Tff7b72= Te6edf3DeviceMetricsTb4b4b4(Tb4b4b4)Tb4b4b4,
Tff7b72val Te6edf3channelTb4b4b4: Tffa657Int Tff7b72= T79c0ff0Tb4b4b4,
Tff7b72val Te6edf3viaMqttTb4b4b4: Tffa657Boolean Tff7b72= Tff7b72falseTb4b4b4,
Tff7b72val Te6edf3hopsAwayTb4b4b4: Tffa657Int Tff7b72= Tff7b72-T79c0ff1Tb4b4b4,
Tff7b72val Te6edf3isFavoriteTb4b4b4: Tffa657Boolean Tff7b72= Tff7b72falseTb4b4b4,
Tff7b72val Te6edf3isIgnoredTb4b4b4: Tffa657Boolean Tff7b72= Tff7b72falseTb4b4b4,
Tff7b72val Te6edf3isMutedTb4b4b4: Tffa657Boolean Tff7b72= Tff7b72falseTb4b4b4,
Tff7b72val Te6edf3environmentMetricsTb4b4b4: Te6edf3EnvironmentMetrics Tff7b72= Te6edf3EnvironmentMetricsTb4b4b4(Tb4b4b4)Tb4b4b4,
Tff7b72val Te6edf3powerMetricsTb4b4b4: Te6edf3PowerMetrics Tff7b72= Te6edf3PowerMetricsTb4b4b4(Tb4b4b4)Tb4b4b4,
Tff7b72val Te6edf3airQualityMetricsTb4b4b4: Te6edf3AirQualityMetrics Tff7b72= Te6edf3AirQualityMetricsTb4b4b4(Tb4b4b4)Tb4b4b4,
Tff7b72val Te6edf3paxcounterTb4b4b4: Te6edf3Paxcount Tff7b72= Te6edf3PaxcountTb4b4b4(Tb4b4b4)Tb4b4b4,
Tff7b72val Te6edf3publicKeyTb4b4b4: Te6edf3ByteString? Tff7b72= Tff7b72nullTb4b4b4,
Tff7b72val Te6edf3notesTb4b4b4: Tffa657String Tff7b72= Ta5d6ff"Ta5d6ff"Tb4b4b4,
T8b949e/** User-editable labels per power-metrics channel (e.g. "Solar", "Battery"), indexed by channel - 1. */
Tff7b72val Te6edf3powerChannelLabelsTb4b4b4: Te6edf3ListTff7b72<Tffa657StringTff7b72> Tff7b72= Te6edf3emptyListTb4b4b4(Tb4b4b4)Tb4b4b4,
Tff7b72val Te6edf3manuallyVerifiedTb4b4b4: Tffa657Boolean Tff7b72= Tff7b72falseTb4b4b4,
T8b949e/** True when this node signs its broadcasts via XEdDSA (NodeInfo.has_xeddsa_signed). Automatic trust. */
Tff7b72val Te6edf3signsPacketsTb4b4b4: Tffa657Boolean Tff7b72= Tff7b72falseTb4b4b4,
Tff7b72val Te6edf3nodeStatusTb4b4b4: Tffa657String? Tff7b72= Tff7b72nullTb4b4b4,
T8b949e/** The transport mechanism this node was last heard over (see [MeshPacket.TransportMechanism]). */
Tff7b72val Te6edf3lastTransportTb4b4b4: Tffa657Int Tff7b72= T79c0ff0Tb4b4b4,
Tb4b4b4) Tb4b4b4{
Tff7b72val Te6edf3capabilitiesTb4b4b4: Te6edf3Capabilities Tff7b72by Te6edf3lazy Tb4b4b4{ Te6edf3CapabilitiesTb4b4b4(Te6edf3metadataTff7b72?.Te6edf3firmware_versionTb4b4b4) Tb4b4b4}
Tff7b72val Te6edf3isOnlineTb4b4b4: Tffa657Boolean
Tff7b72getTb4b4b4(Tb4b4b4) Tff7b72= Te6edf3isOnlineTb4b4b4(Te6edf3onlineTimeThresholdTb4b4b4(Tb4b4b4)Tb4b4b4)
T8b949e/** Injectable [threshold] keeps tests deterministic — the property getter re-reads the clock on every access. */
Tff7b72internal Tff7b72fun Td2a8ffisOnlineTb4b4b4(Te6edf3thresholdTb4b4b4: Tffa657IntTb4b4b4)Tb4b4b4: Tffa657Boolean Tff7b72= Te6edf3lastHeard Tff7b72> Te6edf3threshold
Tff7b72val Te6edf3colorsTb4b4b4: Te6edf3PairTff7b72<Tffa657IntTb4b4b4, Tffa657IntTff7b72>
Tff7b72getTb4b4b4(Tb4b4b4) Tff7b72= Te6edf3nodeColorsFromNumTb4b4b4(Te6edf3numTb4b4b4)
Tff7b72val Te6edf3isUnknownUser
Tff7b72getTb4b4b4(Tb4b4b4) Tff7b72= Te6edf3userTb4b4b4.Te6edf3hw_model Tff7b72=Tff7b72= Te6edf3HardwareModelTb4b4b4.Te6edf3UNSET
Tff7b72val Te6edf3hasPKC
Tff7b72getTb4b4b4(Tb4b4b4) Tff7b72= Tb4b4b4(Te6edf3publicKey Tff7b72?: Te6edf3userTb4b4b4.Te6edf3public_keyTb4b4b4)Tb4b4b4.Te6edf3size Tff7b72> T79c0ff0
Tff7b72val Te6edf3mismatchKey
Tff7b72getTb4b4b4(Tb4b4b4) Tff7b72= Tb4b4b4(Te6edf3publicKey Tff7b72?: Te6edf3userTb4b4b4.Te6edf3public_keyTb4b4b4) Tff7b72=Tff7b72= Te6edf3ERROR_BYTE_STRING
T8b949e/**
* Last measured SNR in dB, or null when this node has no reading yet ([snr] still holds [SNR_UNSET]).
*
* Every read of [snr] should go through this: 0 dB is a real, good reading, and the raw sentinel rates as an
* *excellent* signal if it reaches the preset-relative quality bands. Threshold comparisons such as `snr < 100f`
* are not equivalent — they also discard any genuine reading at or above the threshold.
*/
Tff7b72val Te6edf3snrOrNullTb4b4b4: Tffa657Float?
Tff7b72getTb4b4b4(Tb4b4b4) Tff7b72= Te6edf3snrTb4b4b4.Te6edf3takeIf Tb4b4b4{ Tffa657it Tff7b72!Tff7b72= Te6edf3SNR_UNSET Tb4b4b4}
T8b949e/** Last measured RSSI in dBm, or null when this node has no reading yet. 0 dBm is a real reading. */
Tff7b72val Te6edf3rssiOrNullTb4b4b4: Tffa657Int?
Tff7b72getTb4b4b4(Tb4b4b4) Tff7b72= Te6edf3rssiTb4b4b4.Te6edf3takeIf Tb4b4b4{ Tffa657it Tff7b72!Tff7b72= Te6edf3RSSI_UNSET Tb4b4b4}
Tff7b72val Te6edf3hasEnvironmentMetricsTb4b4b4: Tffa657Boolean
Tff7b72getTb4b4b4(Tb4b4b4) Tff7b72= Te6edf3environmentMetrics Tff7b72!Tff7b72= Te6edf3EnvironmentMetricsTb4b4b4(Tb4b4b4)
Tff7b72val Te6edf3hasPowerMetricsTb4b4b4: Tffa657Boolean
Tff7b72getTb4b4b4(Tb4b4b4) Tff7b72= Te6edf3powerMetrics Tff7b72!Tff7b72= Te6edf3PowerMetricsTb4b4b4(Tb4b4b4)
Tff7b72val Te6edf3hasAirQualityMetricsTb4b4b4: Tffa657Boolean
Tff7b72getTb4b4b4(Tb4b4b4) Tff7b72= Te6edf3airQualityMetrics Tff7b72!Tff7b72= Te6edf3AirQualityMetricsTb4b4b4(Tb4b4b4)
Tff7b72val Te6edf3batteryLevel
Tff7b72getTb4b4b4(Tb4b4b4) Tff7b72= Te6edf3deviceMetricsTb4b4b4.Te6edf3battery_level
Tff7b72val Te6edf3voltage
Tff7b72getTb4b4b4(Tb4b4b4) Tff7b72= Te6edf3deviceMetricsTb4b4b4.Te6edf3voltage
Tff7b72val Te6edf3batteryStr
Tff7b72getTb4b4b4(Tb4b4b4) Tff7b72= Tff7b72if Tb4b4b4(Tb4b4b4(Te6edf3batteryLevel Tff7b72?: T79c0ff0Tb4b4b4) Tff7b72in T79c0ff1.Tb4b4b4.T79c0ff1T79c0ff0T79c0ff0Tb4b4b4) Ta5d6ff"Tffd700$Te6edf3batteryLevelTa5d6ff%Ta5d6ff" Tff7b72else Ta5d6ff"Ta5d6ff"
Tff7b72val Te6edf3latitude
Tff7b72getTb4b4b4(Tb4b4b4) Tff7b72= Tb4b4b4(Te6edf3positionTb4b4b4.Te6edf3latitude_i Tff7b72?: T79c0ff0Tb4b4b4) Tff7b72* T79c0ff1e-7
Tff7b72val Te6edf3longitude
Tff7b72getTb4b4b4(Tb4b4b4) Tff7b72= Tb4b4b4(Te6edf3positionTb4b4b4.Te6edf3longitude_i Tff7b72?: T79c0ff0Tb4b4b4) Tff7b72* T79c0ff1e-7
Tff7b72private Tff7b72fun Td2a8ffhasValidPositionTb4b4b4(Tb4b4b4)Tb4b4b4: Tffa657Boolean Tff7b72= Te6edf3latitude Tff7b72!Tff7b72= T79c0ff0.0 Tff7b72&Tff7b72&
Te6edf3longitude Tff7b72!Tff7b72= T79c0ff0.0 Tff7b72&Tff7b72&
Tb4b4b4(Te6edf3latitude Tff7b72>Tff7b72= Tff7b72-T79c0ff9T79c0ff0 Tff7b72&Tff7b72& Te6edf3latitude Tff7b72<Tff7b72= T79c0ff9T79c0ff0.0Tb4b4b4) Tff7b72&Tff7b72&
Tb4b4b4(Te6edf3longitude Tff7b72>Tff7b72= Tff7b72-T79c0ff1T79c0ff8T79c0ff0 Tff7b72&Tff7b72& Te6edf3longitude Tff7b72<Tff7b72= T79c0ff1T79c0ff8T79c0ff0Tb4b4b4)
Tff7b72val Te6edf3validPositionTb4b4b4: Te6edf3Position?
Tff7b72getTb4b4b4(Tb4b4b4) Tff7b72= Te6edf3positionTb4b4b4.Te6edf3takeIf Tb4b4b4{ Te6edf3hasValidPositionTb4b4b4(Tb4b4b4) Tb4b4b4}
T8b949e// @return distance in meters to some other node (or null if unknown)
Tff7b72fun Td2a8ffdistanceTb4b4b4(Te6edf3oTb4b4b4: Te6edf3NodeTb4b4b4)Tb4b4b4: Tffa657Int? Tff7b72= Tff7b72when Tb4b4b4{
Te6edf3validPosition Tff7b72=Tff7b72= Tff7b72null Tff7b72|Tff7b72| Te6edf3oTb4b4b4.Te6edf3validPosition Tff7b72=Tff7b72= Tff7b72null Tff7b72-Tff7b72> Tff7b72null
Tff7b72else Tff7b72-Tff7b72> Te6edf3latLongToMeterTb4b4b4(Te6edf3latitudeTb4b4b4, Te6edf3longitudeTb4b4b4, Te6edf3oTb4b4b4.Te6edf3latitudeTb4b4b4, Te6edf3oTb4b4b4.Te6edf3longitudeTb4b4b4)Tb4b4b4.Te6edf3toIntTb4b4b4(Tb4b4b4)
Tb4b4b4}
T8b949e// @return formatted distance string to another node, using the given display units
Tff7b72fun Td2a8ffdistanceStrTb4b4b4(Te6edf3oTb4b4b4: Te6edf3NodeTb4b4b4, Te6edf3displayUnitsTb4b4b4: Te6edf3ConfigTb4b4b4.Te6edf3DisplayConfigTb4b4b4.Te6edf3DisplayUnitsTb4b4b4)Tb4b4b4: Tffa657String? Tff7b72=
Te6edf3distanceTb4b4b4(Te6edf3oTb4b4b4)Tff7b72?.Te6edf3toDistanceStringTb4b4b4(Te6edf3displayUnitsTb4b4b4)
T8b949e// @return bearing to the other position in degrees
Tff7b72fun Td2a8ffbearingTb4b4b4(Te6edf3oTb4b4b4: Te6edf3Node?Tb4b4b4)Tb4b4b4: Tffa657Int? Tff7b72= Tff7b72when Tb4b4b4{
Te6edf3validPosition Tff7b72=Tff7b72= Tff7b72null Tff7b72|Tff7b72| Te6edf3oTff7b72?.Te6edf3validPosition Tff7b72=Tff7b72= Tff7b72null Tff7b72-Tff7b72> Tff7b72null
Tff7b72else Tff7b72-Tff7b72> Te6edf3bearingTb4b4b4(Te6edf3latitudeTb4b4b4, Te6edf3longitudeTb4b4b4, Te6edf3oTb4b4b4.Te6edf3latitudeTb4b4b4, Te6edf3oTb4b4b4.Te6edf3longitudeTb4b4b4)Tb4b4b4.Te6edf3toIntTb4b4b4(Tb4b4b4)
Tb4b4b4}
Tff7b72fun Td2a8ffgpsStringTb4b4b4(Tb4b4b4)Tb4b4b4: Tffa657String Tff7b72= Te6edf3GPSFormatTb4b4b4.Te6edf3toDecTb4b4b4(Te6edf3latitudeTb4b4b4, Te6edf3longitudeTb4b4b4)
Tff7b72private Tff7b72fun Te6edf3EnvironmentMetricsTb4b4b4.Td2a8ffgetDisplayStringsTb4b4b4(Te6edf3isFahrenheitTb4b4b4: Tffa657BooleanTb4b4b4)Tb4b4b4: Te6edf3ListTff7b72<Tffa657StringTff7b72> Tb4b4b4{
T8b949e// These fields carry presence: `null` means "no sensor", so 0 °C / 0 V / 0 A / 0% are real readings and must
T8b949e// still render. Humidity keeps its zero-guard because 0% RH is not physically reachable.
Tff7b72val Te6edf3temp Tff7b72= Te6edf3temperatureTff7b72?.Te6edf3let Tb4b4b4{ Te6edf3MetricFormatterTb4b4b4.Te6edf3temperatureTb4b4b4(Tffa657itTb4b4b4, Te6edf3isFahrenheitTb4b4b4) Tb4b4b4}
Tff7b72val Te6edf3humidity Tff7b72= Tff7b72if Tb4b4b4(Tb4b4b4(Te6edf3relative_humidity Tff7b72?: T79c0ff0fTb4b4b4) Tff7b72!Tff7b72= T79c0ff0fTb4b4b4) Te6edf3MetricFormatterTb4b4b4.Te6edf3humidityTb4b4b4(Te6edf3relative_humidity Tff7b72?: T79c0ff0fTb4b4b4) Tff7b72else Tff7b72null
Tff7b72val Te6edf3soilTemperatureStr Tff7b72= Te6edf3soil_temperatureTff7b72?.Te6edf3let Tb4b4b4{ Te6edf3MetricFormatterTb4b4b4.Te6edf3temperatureTb4b4b4(Tffa657itTb4b4b4, Te6edf3isFahrenheitTb4b4b4) Tb4b4b4}
Tff7b72val Te6edf3soilMoistureRange Tff7b72= T79c0ff0.Tb4b4b4.T79c0ff1T79c0ff0T79c0ff0
Tff7b72val Te6edf3soilMoisture Tff7b72= Te6edf3soil_moistureTff7b72?.Te6edf3takeIf Tb4b4b4{ Tffa657it Tff7b72in Te6edf3soilMoistureRange Tb4b4b4}Tff7b72?.Te6edf3let Tb4b4b4{ Te6edf3MetricFormatterTb4b4b4.Te6edf3percentTb4b4b4(Tffa657itTb4b4b4) Tb4b4b4}
Tff7b72val Te6edf3voltage Tff7b72= Tff7b72thisTb4b4b4.Te6edf3voltageTff7b72?.Te6edf3let Tb4b4b4{ Te6edf3MetricFormatterTb4b4b4.Te6edf3voltageTb4b4b4(Tffa657itTb4b4b4) Tb4b4b4}
Tff7b72val Te6edf3current Tff7b72= Te6edf3currentTff7b72?.Te6edf3let Tb4b4b4{ Te6edf3MetricFormatterTb4b4b4.Te6edf3currentTb4b4b4(Tffa657itTb4b4b4) Tb4b4b4}
Tff7b72val Te6edf3iaq Tff7b72= Tff7b72if Tb4b4b4(Tb4b4b4(Te6edf3iaq Tff7b72?: T79c0ff0Tb4b4b4) Tff7b72!Tff7b72= T79c0ff0Tb4b4b4) Ta5d6ff"Ta5d6ffIAQ: Tffd700$Te6edf3iaqTa5d6ff" Tff7b72else Tff7b72null
Tff7b72return Te6edf3listOfNotNullTb4b4b4(
Te6edf3paxcounterTb4b4b4.Te6edf3getDisplayStringTb4b4b4(Tb4b4b4)Tb4b4b4,
Te6edf3tempTb4b4b4,
Te6edf3humidityTb4b4b4,
Te6edf3soilTemperatureStrTb4b4b4,
Te6edf3soilMoistureTb4b4b4,
Te6edf3voltageTb4b4b4,
Te6edf3currentTb4b4b4,
Te6edf3iaqTb4b4b4,
Tb4b4b4)
Tb4b4b4}
Tff7b72private Tff7b72fun Te6edf3PaxcountTb4b4b4.Td2a8ffgetDisplayStringTb4b4b4(Tb4b4b4) Tff7b72= Ta5d6ff"Ta5d6ffPAX: Tffd700${Te6edf3ble Tff7b72+ Te6edf3wifiTffd700}Ta5d6ff (B:Tffd700$Te6edf3bleTa5d6ff/W:Tffd700$Te6edf3wifiTa5d6ff)Ta5d6ff"Tb4b4b4.Te6edf3takeIf Tb4b4b4{ Te6edf3ble Tff7b72!Tff7b72= T79c0ff0 Tff7b72|Tff7b72| Te6edf3wifi Tff7b72!Tff7b72= T79c0ff0 Tb4b4b4}
Tff7b72fun Td2a8ffgetTelemetryStringsTb4b4b4(Te6edf3isFahrenheitTb4b4b4: Tffa657Boolean Tff7b72= Tff7b72falseTb4b4b4)Tb4b4b4: Te6edf3ListTff7b72<Tffa657StringTff7b72> Tff7b72=
Te6edf3environmentMetricsTb4b4b4.Te6edf3getDisplayStringsTb4b4b4(Te6edf3isFahrenheitTb4b4b4)
Tff7b72companion Tff7b72object Tb4b4b4{
Tff7b72private Tff7b72const Tff7b72val Te6edf3DEFAULT_ID_SUFFIX_LENGTH Tff7b72= T79c0ff4
Tff7b72private Tff7b72const Tff7b72val Te6edf3RELAY_NODE_SUFFIX_MASK Tff7b72= T79c0ff0Te6edf3xFF
T8b949e/** Size (in bytes) of a Curve25519 public key as used by meshtastic firmware. */
Tff7b72const Tff7b72val Te6edf3PUBLIC_KEY_SIZETb4b4b4: Tffa657Int Tff7b72= T79c0ff3T79c0ff2
T8b949e/**
* Sentinels stored when a node has no radio-metric reading. They exist because [snr]/[rssi] are not nullable
* (the Room columns behind them are NOT NULL); resolve them with [snrOrNull]/[rssiOrNull] rather than comparing
* against them at call sites.
*/
Tff7b72const Tff7b72val Te6edf3SNR_UNSETTb4b4b4: Tffa657Float Tff7b72= Tffa657FloatTb4b4b4.Te6edf3MAX_VALUE
Tff7b72const Tff7b72val Te6edf3RSSI_UNSETTb4b4b4: Tffa657Int Tff7b72= Tffa657IntTb4b4b4.Te6edf3MAX_VALUE
Tff7b72val Te6edf3ERROR_BYTE_STRINGTb4b4b4: Te6edf3ByteString Tff7b72= Te6edf3ByteArrayTb4b4b4(Te6edf3PUBLIC_KEY_SIZETb4b4b4) Tb4b4b4{ T79c0ff0 Tb4b4b4}Tb4b4b4.Te6edf3toByteStringTb4b4b4(Tb4b4b4)
Tff7b72fun Td2a8ffgetRelayNodeTb4b4b4(Te6edf3relayNodeIdTb4b4b4: Tffa657IntTb4b4b4, Te6edf3nodesTb4b4b4: Te6edf3ListTff7b72<Te6edf3NodeTff7b72>Tb4b4b4, Te6edf3ourNodeNumTb4b4b4: Tffa657Int?Tb4b4b4)Tb4b4b4: Te6edf3Node? Tb4b4b4{
Tff7b72val Te6edf3relayNodeIdSuffix Tff7b72= Te6edf3relayNodeId Te6edf3and Te6edf3RELAY_NODE_SUFFIX_MASK
Tff7b72val Te6edf3candidateRelayNodes Tff7b72=
Te6edf3nodesTb4b4b4.Te6edf3filter Tb4b4b4{
Tffa657itTb4b4b4.Te6edf3num Tff7b72!Tff7b72= Te6edf3ourNodeNum Tff7b72&Tff7b72&
Tffa657itTb4b4b4.Te6edf3lastHeard Tff7b72!Tff7b72= T79c0ff0 Tff7b72&Tff7b72&
Tb4b4b4(Tffa657itTb4b4b4.Te6edf3num Te6edf3and Te6edf3RELAY_NODE_SUFFIX_MASKTb4b4b4) Tff7b72=Tff7b72= Te6edf3relayNodeIdSuffix
Tb4b4b4}
Tff7b72val Te6edf3closestRelayNode Tff7b72=
Tff7b72if Tb4b4b4(Te6edf3candidateRelayNodesTb4b4b4.Te6edf3size Tff7b72=Tff7b72= T79c0ff1Tb4b4b4) Tb4b4b4{
Te6edf3candidateRelayNodesTb4b4b4.Te6edf3firstTb4b4b4(Tb4b4b4)
Tb4b4b4} Tff7b72else Tb4b4b4{
Te6edf3candidateRelayNodesTb4b4b4.Te6edf3minByOrNull Tb4b4b4{ Tffa657itTb4b4b4.Te6edf3hopsAway Tb4b4b4}
Tb4b4b4}
Tff7b72return Te6edf3closestRelayNode
Tb4b4b4}
T8b949e/** Creates a fallback [Node] when the node is not found in the database. */
Tff7b72fun Td2a8ffcreateFallbackTb4b4b4(Te6edf3nodeNumTb4b4b4: Tffa657IntTb4b4b4, Te6edf3fallbackNamePrefixTb4b4b4: Tffa657StringTb4b4b4)Tb4b4b4: Te6edf3Node Tb4b4b4{
Tff7b72val Te6edf3userId Tff7b72= Te6edf3NodeAddressTb4b4b4.Te6edf3numToDefaultIdTb4b4b4(Te6edf3nodeNumTb4b4b4)
Tff7b72val Te6edf3safeUserId Tff7b72= Te6edf3userIdTb4b4b4.Te6edf3padStartTb4b4b4(Te6edf3DEFAULT_ID_SUFFIX_LENGTHTb4b4b4, Ta5d6ff'0'Tb4b4b4)Tb4b4b4.Te6edf3takeLastTb4b4b4(Te6edf3DEFAULT_ID_SUFFIX_LENGTHTb4b4b4)
Tff7b72val Te6edf3longName Tff7b72= Ta5d6ff"Tffd700$Te6edf3fallbackNamePrefixTa5d6ff Tffd700$Te6edf3safeUserIdTa5d6ff"
Tff7b72val Te6edf3defaultUser Tff7b72=
Te6edf3UserTb4b4b4(Te6edf3id Tff7b72= Te6edf3userIdTb4b4b4, Te6edf3long_name Tff7b72= Te6edf3longNameTb4b4b4, Te6edf3short_name Tff7b72= Te6edf3safeUserIdTb4b4b4, Te6edf3hw_model Tff7b72= Te6edf3HardwareModelTb4b4b4.Te6edf3UNSETTb4b4b4)
Tff7b72return Te6edf3NodeTb4b4b4(Te6edf3num Tff7b72= Te6edf3nodeNumTb4b4b4, Te6edf3user Tff7b72= Te6edf3defaultUserTb4b4b4)
Tb4b4b4}
Tb4b4b4}
Tb4b4b4}
Tff7b72fun Te6edf3ConfigTb4b4b4.Td2a8ffDeviceConfigTb4b4b4.Te6edf3RoleTff7b72?.Te6edf3isUnmessageableRoleTb4b4b4(Tb4b4b4)Tb4b4b4: Tffa657Boolean Tff7b72= Tff7b72this Tff7b72in
Te6edf3listOfTb4b4b4(
Te6edf3ConfigTb4b4b4.Te6edf3DeviceConfigTb4b4b4.Te6edf3RoleTb4b4b4.Te6edf3REPEATERTb4b4b4,
Te6edf3ConfigTb4b4b4.Te6edf3DeviceConfigTb4b4b4.Te6edf3RoleTb4b4b4.Te6edf3ROUTERTb4b4b4,
Te6edf3ConfigTb4b4b4.Te6edf3DeviceConfigTb4b4b4.Te6edf3RoleTb4b4b4.Te6edf3ROUTER_LATETb4b4b4,
Te6edf3ConfigTb4b4b4.Te6edf3DeviceConfigTb4b4b4.Te6edf3RoleTb4b4b4.Te6edf3SENSORTb4b4b4,
Te6edf3ConfigTb4b4b4.Te6edf3DeviceConfigTb4b4b4.Te6edf3RoleTb4b4b4.Te6edf3TRACKERTb4b4b4,
Te6edf3ConfigTb4b4b4.Te6edf3DeviceConfigTb4b4b4.Te6edf3RoleTb4b4b4.Te6edf3TAK_TRACKERTb4b4b4,
Tb4b4b4)
T8b949e/** Offset converting a negative [Node.num] into its unsigned 32-bit decimal representation. */
Tff7b72private Tff7b72const Tff7b72val Te6edf3UNSIGNED_INT_OFFSET Tff7b72= T79c0ff4T79c0ff2T79c0ff9T79c0ff4T79c0ff9T79c0ff6T79c0ff7T79c0ff2T79c0ff9T79c0ff6L
Tff7b72private Tff7b72val Te6edf3NodeTb4b4b4.Te6edf3unsignedNumTb4b4b4: Tffa657Long
Tff7b72getTb4b4b4(Tb4b4b4) Tff7b72= Te6edf3numTb4b4b4.Te6edf3toLongTb4b4b4(Tb4b4b4)Tb4b4b4.Te6edf3let Tb4b4b4{ Tff7b72if Tb4b4b4(Tffa657it Tff7b72< T79c0ff0Tb4b4b4) Tffa657it Tff7b72+ Te6edf3UNSIGNED_INT_OFFSET Tff7b72else Tffa657it Tb4b4b4}
T8b949e/**
* Matches node search text (long/short name, hex id, decimal id) with Unicode-aware case folding.
*
* Must run in Kotlin, not SQL: SQLite's LIKE/UPPER/LOWER only case-fold ASCII a-z/A-Z, so a query like "kolså" can
* never match a stored name of "KOLSÅS" via a SQL WHERE clause (#6750).
*/
Tff7b72fun Te6edf3NodeTb4b4b4.Td2a8ffmatchesSearchTb4b4b4(Te6edf3filterTb4b4b4: Tffa657StringTb4b4b4)Tb4b4b4: Tffa657Boolean Tff7b72= Te6edf3filterTb4b4b4.Te6edf3isBlankTb4b4b4(Tb4b4b4) Tff7b72|Tff7b72|
Te6edf3userTb4b4b4.Te6edf3long_nameTb4b4b4.Te6edf3containsTb4b4b4(Te6edf3filterTb4b4b4, Te6edf3ignoreCase Tff7b72= Tff7b72trueTb4b4b4) Tff7b72|Tff7b72|
Te6edf3userTb4b4b4.Te6edf3short_nameTb4b4b4.Te6edf3containsTb4b4b4(Te6edf3filterTb4b4b4, Te6edf3ignoreCase Tff7b72= Tff7b72trueTb4b4b4) Tff7b72|Tff7b72|
Te6edf3userTb4b4b4.Te6edf3idTb4b4b4.Te6edf3containsTb4b4b4(Te6edf3filterTb4b4b4, Te6edf3ignoreCase Tff7b72= Tff7b72trueTb4b4b4) Tff7b72|Tff7b72|
Te6edf3unsignedNumTb4b4b4.Te6edf3toStringTb4b4b4(Tb4b4b4)Tb4b4b4.Te6edf3containsTb4b4b4(Te6edf3filterTb4b4b4, Te6edf3ignoreCase Tff7b72= Tff7b72trueTb4b4b4)
Served by rngit 1.5.0 - Generated in 0.09s